﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.Xml;

namespace Useful.GUI
{
    public partial class RegionMap : UserControl
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected struct RegionColor
        {
            public Color UnSelectedRegionColor;
            public Color SelectedRegionColor;

            public RegionColor(Color UnSelectedRegionColor, Color SelectedRegionColor)
            {
                this.UnSelectedRegionColor = UnSelectedRegionColor;
                this.SelectedRegionColor = SelectedRegionColor;
            }
        }

        protected Dictionary<int, RegionMapItem> regions = new Dictionary<int, RegionMapItem>();
        protected Dictionary<string, RegionMapItem> helpRegions = new Dictionary<string, RegionMapItem>();
        protected Bitmap bmpMap;
        protected Bitmap bmpContur;
        protected ToolTip tooltip = new ToolTip();
        protected Color UnSelectedRegionColor;
        protected Color SelectedRegionColor;

        private void InitMap(Bitmap bmpMap, Bitmap bmpContur)
        {
            if (bmpMap != null && bmpContur != null && bmpContur.Width != 0 && bmpContur.Height != 0 && bmpMap.Width != 0 && bmpMap.Height != 0)
            {
                this.bmpMap = bmpMap;
                this.bmpContur = bmpContur;

                this.Width = bmpMap.Width;
                this.Height = bmpMap.Height;
            }
            else
                throw new ArgumentNullException("bmpMap или bmpContur");
        }

        public RegionMapItem this[string name]
        {
            get
            {
                return helpRegions[name];
            }
        }

        public string[] Regions
        {
            get
            {
                List<string> list = new List<string>();

                foreach (RegionMapItem region in regions.Values)
                    list.Add(region.Name);

                return list.ToArray();
            }
        }

        protected RegionMapItem GetRegion(int x, int y)
        {
            RegionMapItem res = null;

            if (x >= 0 && y >= 0 && x < bmpMap.Width && y < bmpMap.Height)
            {
                Color c = bmpMap.GetPixel(x, y);
                int argb = c.ToArgb();

                regions.TryGetValue(argb, out res);
                if (res != null && !res.Visible)
                    res = null;
            }

            return res;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            foreach (RegionMapItem region in regions.Values)
                region.Paint(e.Graphics);

            e.Graphics.DrawImage(bmpContur, 0, 0);
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                RegionMapItem region = GetRegion(e.X, e.Y);

                if (region != null)
                {
                    region.Selected = !region.Selected;
                }
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            RegionMapItem region = GetRegion(e.X, e.Y);

            tooltip.Show(region != null ? region.Name : null, this, e.Location + new Size(8, 3));
        }

        protected void AddRegion(Color color, RegionMapItem region, string name)
        {
            try
            {
                regions.Add(color.ToArgb(), region);
                helpRegions.Add(name, region);

                region.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(region_PropertyChanged);
            }
            catch (ArgumentException ex)
            {
                throw new ArgumentException("Регион с таким цветом уже есть в словаре: " + ex.Message, ex);
            }
        }

        private void region_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            using (Graphics g = CreateGraphics())
            {
                ((RegionMapItem)sender).Paint(g);
            }

            NotifyPropertyChanged(((RegionMapItem)sender).Name);
        }

        protected Color GetColor(string str)
        {
            Color res = Color.FromName(str);

            if (res.ToArgb() == Color.Empty.ToArgb())
                throw new Exception(String.Format("Не найден цвет: " + str));

            return res;
        }

        protected void LoadMap(string xmlString)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlString);

            UnSelectedRegionColor = GetColor(doc.DocumentElement["UnSelectedRegionColor"].InnerText);
            SelectedRegionColor = GetColor(doc.DocumentElement["SelectedRegionColor"].InnerText);

            Bitmap contur = (Bitmap)GuiHelper.ResourceManager.GetObject(doc.DocumentElement["ConturMap"].InnerText, null);
            Bitmap map = new Bitmap(contur.Width, contur.Height);
            
            Graphics g = Graphics.FromImage(map);
            g.Clear(Color.Transparent);

            Dictionary<string, RegionColor> okrugs = new Dictionary<string,RegionColor>();

            foreach (XmlNode okrug in doc.DocumentElement["Okrugs"].ChildNodes)
            {
                Color _SelectedRegionColor = GetColor(okrug.Attributes["SelectedRegionColor"].InnerText);
                Color _UnSelectedRegionColor = GetColor(okrug.Attributes["UnSelectedRegionColor"].InnerText);

                foreach (XmlNode reg in okrug.ChildNodes)
                {
                    string name = reg.InnerText;
                    okrugs[name] = new RegionColor(_UnSelectedRegionColor, _SelectedRegionColor);
                }
            }

            foreach (XmlNode node in doc.DocumentElement["Regions"].ChildNodes)
            {
                Color _UnSelectedRegionColor;
                Color _SelectedRegionColor;
                RegionColor rc;

                if (okrugs.TryGetValue(node["Name"].InnerText, out rc))
                {
                    _UnSelectedRegionColor = rc.UnSelectedRegionColor;
                    _SelectedRegionColor = rc.SelectedRegionColor;
                }
                else
                {
                    _UnSelectedRegionColor = this.UnSelectedRegionColor;
                    _SelectedRegionColor = this.SelectedRegionColor;
                }

                RegionMapItem region = new RegionMapItem();
                Color c = region.Load(node, _UnSelectedRegionColor, _SelectedRegionColor);

                if (region.Image != null)
                {
                    AddRegion(c, region, region.Name);

                    g.DrawImage(GDI.ReplaceColor(new Bitmap(region.Image), c), region.Location);
                }
            }

            InitMap(map, contur);
        }

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }
}
